﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace suidtool
{
    public partial class MainForm : Form
    {
        private FileInfo mkvi, mkvpe;
        private static Regex stripHex = new Regex(@"(?:0x|[^a-fA-F0-9])");
        private static Regex mkviMatch = new Regex(@"Segment UID: ((?:\s*(?:0x)?[a-fA-F0-9]{2}){16})");
        private SuidEditor suidEditor = new SuidEditor();

        public MainForm()
        {
            InitializeComponent();
            
            autoClipboard.Checked = Properties.Settings.Default.autoClipboard;
            keepTopmost.Checked = Properties.Settings.Default.keepTopmost;
            if (!validateToolsPath(Properties.Settings.Default.mkvtlPath))
            {
                Properties.Settings.Default.mkvtlPath = "";
            }
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            Properties.Settings.Default.autoClipboard = autoClipboard.Checked;
            Properties.Settings.Default.keepTopmost = keepTopmost.Checked;
            if (mkvi != null)
                Properties.Settings.Default.mkvtlPath = mkvi.Directory.FullName;
            else
                Properties.Settings.Default.mkvtlPath = "";
            Properties.Settings.Default.Save();

            base.OnFormClosing(e);
        }

        private void SetEnabledState(bool bEnable)
        {
            foreach (Control c in this.Controls)
            {
                c.Enabled = bEnable;
            }
        }

        private bool hasTools()
        {
            return mkvi != null && mkvpe != null;
        }

        private bool validateToolsPath(string path)
        {
            if (path == null || path.Length == 0)
                return false;
            try
            {
                mkvi = new FileInfo(path + Path.DirectorySeparatorChar + "mkvinfo.exe");
                mkvpe = new FileInfo(path + Path.DirectorySeparatorChar + "mkvpropedit.exe");
                if (mkvi.Exists && mkvpe.Exists)
                {
                    mkvtlFolderText.Text = path;
                    mainPanel.Enabled = true;
                    return true;
                }
            }
            catch (Exception err)
            {
                MessageBox.Show("Error: " + err.ToString(), null,
                                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }

            mkvi = mkvpe = null;
            MessageBox.Show("Folder specified does not have required executables " +
                            "(mkvinfo.exe, mkvpropedit.exe)", null,
                            MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

            mkvtlFolderText.Text = null;
            mainPanel.Enabled = false;
            return false;
        }

        private void OnAddFiles(object sender, DoWorkEventArgs e)
        {   
            if (!hasTools())
            {
                MessageBox.Show("Set mkvtoolnix path first!", null, 
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            string[] files = e.Argument as string[];
            List<ListViewItem> items = new List<ListViewItem>();
            Action<ListViewItem> updateList = (lvi) => { fileList.Items.Add(lvi); };

            foreach (string file in files)
            {
                FileInfo fi = new FileInfo(file);
                if (!fi.Exists)
                    continue;

                using (Process p = new Process())
                {
                    p.StartInfo.FileName = mkvi.FullName;
                    p.StartInfo.Arguments = "\"" + fi.FullName + "\"";
                    p.StartInfo.UseShellExecute = false;
                    p.StartInfo.RedirectStandardOutput = true;
                    p.StartInfo.CreateNoWindow = true;

                    p.Start();

                    string output = p.StandardOutput.ReadToEnd();
                    p.WaitForExit();
                    if (p.ExitCode == 0)
                    {
                        foreach (Match m in mkviMatch.Matches(output))
                        {
                            string suid = stripHex.Replace(m.Groups[1].ToString(), "");
                            if (suid.Length == 32)
                            {
                                ListViewItem lvi = new ListViewItem(fi.Name);
                                lvi.SubItems.Add(suid);
                                lvi.Tag = fi;
                                items.Add(lvi);
                                fileList.Invoke(updateList, lvi);
                            }
                        }
                    }
                } //End process execution
            } //End file iteration

            this.Invoke(new Action(() => { updateClipboard(items, false); }));
        } //End OnAddFiles

        private void updateClipboard(IList<ListViewItem> items, bool bForce)
        {
            if (autoClipboard.Checked || bForce)
            {
                if (items.Count == 1)
                    Clipboard.SetText(items[0].SubItems[1].Text);
                else if (items.Count > 1)
                {
                    StringBuilder sb = new StringBuilder(items[0].SubItems[1].Text);
                    for (int i = 1; i < items.Count; i++)
                        sb.Append(",").Append(items[i].SubItems[1].Text);
                    Clipboard.SetText(sb.ToString());
                }
            }
        }

        #region FormEvents
        private void keepTopmost_CheckedChanged(object sender, EventArgs e)
        {
            this.TopMost = keepTopmost.Checked;
        }

        private void mkvtlBrowse_Click(object sender, EventArgs e)
        {
            DialogResult result = mkvtlBrowseDialog.ShowDialog(this);
            if (result == DialogResult.OK)
            {
                validateToolsPath(mkvtlBrowseDialog.SelectedPath);
            }
        }

        private void addButton_Click(object sender, EventArgs e)
        {
            DialogResult result = addFileDialog.ShowDialog(this);

            if (result == DialogResult.OK && !backgroundFileAdder.IsBusy)
            {
                SetEnabledState(false);
                backgroundFileAdder.RunWorkerAsync(addFileDialog.FileNames);
            }
        }

        private void fileList_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Move;
            else
                e.Effect = DragDropEffects.None;
        }

        private void fileList_DragDrop(object sender, DragEventArgs e)
        {
            if (!backgroundFileAdder.IsBusy)
            {
                String[] s = e.Data.GetData(DataFormats.FileDrop) as String[];
                SetEnabledState(false);
                backgroundFileAdder.RunWorkerAsync(s);
            }
        }

        private void operation_Complete(object sender, RunWorkerCompletedEventArgs e)
        {
            SetEnabledState(true);
        }

        private void clearButton_Click(object sender, EventArgs e)
        {
            fileList.Items.Clear();
        }

        private void removeButton_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem lvi in fileList.SelectedItems)
                fileList.Items.Remove(lvi);
        }

        private void fileList_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            updateClipboard(fileList.SelectedItems.Cast<ListViewItem>().ToList(), false);
        }

        private void copySUIDToolStripMenuItem_Click(object sender, EventArgs e)
        {
            updateClipboard(fileList.SelectedItems.Cast<ListViewItem>().ToList(), true);
        }

        private void fileList_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Return)
            {
                editSuid_Click(sender, e);
            }
        }

        private void editSuid_Click(object sender, EventArgs e)
        {
            List<ListViewItem> items = new List<ListViewItem>();

            SetEnabledState(false);
            foreach (ListViewItem lvi in fileList.SelectedItems)
            {
                string path = ((FileInfo)lvi.Tag).FullName;
                if (suidEditor.Show(path, lvi.SubItems[1].Text, mkvpe) == DialogResult.OK)
                {
                    items.Add(lvi);
                    lvi.SubItems[1].Text = suidEditor.UserSuid;
                }
            }

            updateClipboard(items, false);
            SetEnabledState(true);
        }
        #endregion
    }
}
